package com.qmscy.sparrow.service.impl;

import com.qmscy.sparrow.common.constant.AssertMessage;
import com.qmscy.sparrow.common.exception.PasswordMismatchException;
import com.qmscy.sparrow.common.util.DateConvertUtil;
import com.qmscy.sparrow.common.util.MD5Util;
import com.qmscy.sparrow.common.util.ValidateUtil;
import com.qmscy.sparrow.domain.User;
import com.qmscy.sparrow.repository.UserDao;
import com.qmscy.sparrow.service.UserService;
import java.util.Date;
import java.util.NoSuchElementException;
import java.util.Optional;
import javax.annotation.Resource;
import javax.transaction.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

@Service
@Transactional
public class UserServiceImpl implements UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @Resource
    private UserDao userDao;

    @Override
    public User findById(Integer id) {
        logger.info("[UserServiceImpl.findById] - id:{}", id);
        Assert.notNull(id, AssertMessage.NOT_NULL_ID);
        Optional<User> optional = userDao.findById(id);
        return optional.orElse(null);
    }

    @Override
    public User save(User entity) {
        Assert.notNull(entity, AssertMessage.NOT_NULL_PARAM);
        Assert.notNull(entity.getPassword(), AssertMessage.NOT_NULL_PASSWORD);
        logger.info("[UserServiceImpl.save] - user:{}", entity);
        // init entity
        Date now = new Date();
        String salt = DateConvertUtil.getSaltStr(now);
        String pw = MD5Util.MD5_32bit(entity.getPassword() + salt);
        entity.setPassword(pw);
        entity.setCreatedTime(now);
        entity.setUpdatedTime(now);

        return userDao.save(entity);
    }

    @Override
    public void deleteById(Integer id) {
        logger.info("[UserServiceImpl.deleteById] - id:{}", id);
        Assert.notNull(id, AssertMessage.NOT_NULL_ID);
        userDao.deleteById(id);
    }

    @Override
    public User update(User entity) {
        Assert.notNull(entity, AssertMessage.NOT_NULL_ID);
        Assert.notNull(entity.getId(), AssertMessage.NOT_NULL_PRIMARY);
        logger.info("[UserServiceImpl.update] - user:{}", entity);
        return userDao.save(entity);
    }

    @Override
    public User loginInfoValidate(String username, String password) throws PasswordMismatchException,
            NoSuchElementException {
        logger.info("[UserServiceImpl.loginInfoValidate] - username:{}, password:{}", username, password);
        Assert.notNull(username, AssertMessage.NOT_NULL_PARAM);
        Assert.notNull(password, AssertMessage.NOT_NULL_PARAM);
        Optional<User> optional;
        if (ValidateUtil.isValidUsername(username)) {
            optional = userDao.findByUsername(username);
        } else if (ValidateUtil.isMobileNo(username)) {
            optional = userDao.findByUsername(username);
        } else if (ValidateUtil.isEmail(username)) {
            optional = userDao.findByUsername(username);
        } else {
            optional = Optional.empty();
        }

        // validate user
        User user = optional.orElseThrow(() -> new NoSuchElementException("user not found"));
        // validate password
        String salt = DateConvertUtil.getSaltStr(user.getCreatedTime());
        String pw = MD5Util.MD5_32bit(password + salt);
        if (!password.equals(pw)) {
            throw new PasswordMismatchException("password do not match");
        }
        return user;
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        logger.info("[UserServiceImpl.loadUserByUsername] - username:{}", username);
        Assert.notNull(username, AssertMessage.NOT_NULL_USERNAME);
        Optional<User> optional;
        if (ValidateUtil.isValidUsername(username)) {
            optional = userDao.findByUsername(username);
        } else if (ValidateUtil.isMobileNo(username)) {
            optional = userDao.findByUsername(username);
        } else if (ValidateUtil.isEmail(username)) {
            optional = userDao.findByUsername(username);
        } else {
            optional = Optional.empty();
        }

        // validate user
        return optional.orElseThrow(() -> new UsernameNotFoundException("user not found"));
    }
}
